﻿using System;
using FlickrXplorer.Web.Models;
using FlickrXplorer.Web.Objects;
using FlickrXplorer.Web.Plugin.Exceptions;

// DEMO 1
namespace FlickrXplorer.Web.Plugin
{
  /// <summary>
  /// The base class for creating a FlickrXplorer plugin.
  /// </summary>
  /// <value>
  /// All FlickrXplorer plugins must inherit from this class in
  /// order to add content to the main page. There are two content
  /// sections available for rendering content. You must render to
  /// at least one of these sections.
  /// </value>
  /// <example>
  /// This is a plugin that writes <b>Hello World</b> above the
  /// main photograph and in the sidebar above the thumbnail
  /// control.
  /// 
  /// <code lang="c#">
  /// public class HelloWorld : FlickrXplorerPlugin
  /// {
  ///   public HelloWorld() : base(&quot;Hello World&quot;)
  ///   {
  ///     this.LoadMainPhoto += new EventHandler&lt;LoadMainPhotoEventArgs&gt;(HelloWorld_LoadMainPhoto);
  ///     this.LoadSideBar += new EventHandler&lt;LoadSidebarEventArgs&gt;(HelloWorld_LoadSideBar);
  ///   }
  /// 
  ///   private void HelloWorld_LoadMainPhoto(object sender, LoadMainPhotoEventArgs e)
  ///   {
  ///     e.Content = &quot;Hello World!&quot;;
  ///   }
  /// 
  ///   private void HelloWorld_LoadSideBar(object sender, LoadSidebarEventArgs e)
  ///   {
  ///     e.Content = &quot;Hello World!&quot;;
  ///   }
  /// }
  /// 
  /// </code>
  /// </example>
  /// <see cref="FlickrXplorer.Web.Plugin.SidebarPlugin" text="SidebarPlugin Class" />
  /// 
  /// <see cref="FlickrXplorer.Web.Plugin.LoadMainPhotoEventArgs" text="LoadMainPhotoEventArgs Class" />
  /// 
  /// <see cref="FlickrXplorer.Web.Plugin.LoadSidebarEventArgs" text="LoadSidebarEventArgs Class" />     
  public abstract class FlickrXplorerPlugin
  {
    /// <summary>
    /// Gets the plugin name, as set in the <see cref="FlickrXplorer.Web.Plugin.FlickrXplorerPlugin.FlickrXplorerPlugin@string" text="Constructor" />
    /// of the child class.
    /// </summary>                                                                                                                                   
    public string Name { get; private set; }
    /// <summary>
    /// Gets a unique Id for this plugin.
    /// </summary>
    /// <remarks>
    /// The plugin Id is simply the <see cref="FlickrXplorer.Web.Plugin.FlickrXplorerPlugin.Name" text="Name" />
    /// with the spaces replaced by underscores.
    /// </remarks>                                                                                              
    public string Id { get; private set; }
    /// <summary>
    /// Gets or sets the <see cref="FlickrXplorer.Web.Plugin.FlickrXplorerPlugin.PluginStatus" text="Status" />
    /// of this plugin.
    /// </summary>
    /// <remarks>
    /// <see cref="FlickrXplorer.Web.Plugin.PluginStatus.Disabled" text="Disabled" />
    /// plugins are not rendered in Flickr Xplorer.
    /// </remarks>                                                                                             
    public PluginStatus PluginStatus { get; internal set; }
    /// <summary>
    /// Gets an instance of the <see cref="FlickrXplorer.Web.Models.IPhotoModel" text="IPhotoModel" />
    /// that allows you to interact with the Flickr API.
    /// </summary>                                                                                    
    protected IPhotoModel PhotoModel { get; private set; }
    
    /// <summary>
    /// Fired when the page is busy rendering the main photograph.
    /// </summary>
    /// <see cref="FlickrXplorer.Web.Plugin.LoadMainPhotoEventArgs" text="LoadMainPhotoEventArgs Class" />
    /// 
    /// <see cref="FlickrXplorer.Web.Plugin.FlickrXplorerPlugin.LoadSideBar" text="FlickrXplorerPlugin.LoadSideBar Event" />
    /// 
    /// <see cref="FlickrXplorer.Web.Plugin.LoadSidebarEventArgs" text="LoadSidebarEventArgs Class" />                      
    public event EventHandler<LoadMainPhotoEventArgs> LoadMainPhoto;
    /// <summary>
    /// Fired when the page is busy rendering the main photograph.
    /// </summary>
    /// <see cref="FlickrXplorer.Web.Plugin.LoadSidebarEventArgs" text="LoadSidebarEventArgs Class" />
    /// 
    /// <see cref="FlickrXplorer.Web.Plugin.FlickrXplorerPlugin.LoadMainPhoto" text="FlickrXplorerPlugin.LoadMainPhoto Event" />
    /// 
    /// <see cref="FlickrXplorer.Web.Plugin.LoadMainPhotoEventArgs" text="LoadMainPhotoEventArgs Class" />                      
    public event EventHandler<LoadSidebarEventArgs> LoadSideBar;

    /// <summary>
    /// Creates a new instance of <see cref="FlickrXplorer.Web.Plugin.FlickrXplorerPlugin" text="FlickrXplorerPlugin" />
    /// and gives it a name.
    /// </summary>
    /// <param name="name">The plugin name, as specified by the
    ///                    child class</param>                                                                          
    public FlickrXplorerPlugin(string name)
    {
      this.PluginStatus = PluginStatus.Enabled;
      this.Name = name;
      this.Id = name.Replace(" ", "_").Trim();
      this.PhotoModel = new PhotoModel();
    }

    /// <summary>
    /// Makes sure that the plugin is in a valid state.
    /// </summary>
    /// <remarks>
    /// A plugin is only valid if it has a <see cref="FlickrXplorer.Web.Plugin.FlickrXplorerPlugin.Name" text="name" />
    /// and handles either the <see cref="FlickrXplorer.Web.Plugin.FlickrXplorerPlugin.LoadSideBar" text="LoadSideBar" />
    /// or <see cref="FlickrXplorer.Web.Plugin.FlickrXplorerPlugin.LoadMainPhoto" text="LoadMainPhoto" />
    /// event.
    /// 
    /// 
    /// </remarks>                                                                                                       
    internal void EnsurePluginState()
    {
      if (String.IsNullOrEmpty(this.Name))
      {
        throw new ArgumentNullException("Name", "A plugin name was expected but it was null or empty. Please specify a valid name for this plugin.");
      }

      if (this.LoadMainPhoto == null && this.LoadSideBar == null)
      {
        throw new PluginHasNoEventHandlersException(this);
      }
    }

    /// <summary>
    /// Called when the main photo section is being rendered. It will
    /// invoke the <see cref="FlickrXplorer.Web.Plugin.FlickrXplorerPlugin.LoadMainPhoto" text="LoadMainPhoto" />
    /// event.
    /// </summary>
    /// <param name="contentSection">The content section to save the
    ///                              \output to.</param>
    /// <param name="photoDetail">Holds information about the
    ///                           main photograph.</param>                                                       
    internal bool OnLoadMainPhoto(ContentSection contentSection, PhotoDetail photoDetail)
    {
      bool hasContent = false;

      if (this.PluginStatus == PluginStatus.Enabled)
      {
        EnsurePluginState();

        try
        {
          EventHandler<LoadMainPhotoEventArgs> handler = this.LoadMainPhoto;
          if (handler != null)
          {
            handler(this, new LoadMainPhotoEventArgs(contentSection, photoDetail));
            hasContent = true;
          }
        }
        catch (Exception ex)
        {
          throw new PluginExecutionException(this, ex);
        }
      }

      return hasContent;
    }

    /// <summary>
    /// Called when the sidebar section is being rendered. It will
    /// invoke the <see cref="FlickrXplorer.Web.Plugin.FlickrXplorerPlugin.LoadSideBar" text="LoadSideBar" />
    /// event.
    /// </summary>
    /// <param name="contentSection">The content section to save the
    ///                              \output to.</param>
    /// <param name="photoData">Holds information about related
    ///                         photographs.</param>                                                         
    internal bool OnLoadSideBar(ContentSection contentSection, PhotoData photoData)
    {
      bool hasContent = false;

      if (this.PluginStatus == PluginStatus.Enabled)
      {
        EnsurePluginState();

        try
        {
          EventHandler<LoadSidebarEventArgs> handler = this.LoadSideBar;
          if (handler != null)
          {
            handler(this, new LoadSidebarEventArgs(contentSection, photoData));
            hasContent = true;
          }
        }
        catch (Exception ex)
        {
          throw new PluginExecutionException(this, ex);
        }
      }

      return hasContent;
    }
  }
}
